import pprint
from datetime import datetime

import orjson
from elasticsearch.helpers import async_scan
from api.search.utils import bool_institution_query
from config import aredis
from core.es import Index_KJJ_DEPARTMENT, Index_KJJ_ACTIVITY_REGISTER, Index_KJJ_ALUMNI
from utils.es import es_client


def get_quarter_aggs(year: int):
    """
    人才详情： 人才参与活动数量 by_quarter
    """
    cur_year = year if year else datetime.utcnow().year
    aggs = {
        "year_filter": {
            "filter": {
                "term": {
                    "range_year": cur_year
                }
            },
            "aggs": {
                "by_current_year_quarter": {
                    "date_histogram": {
                        "field": "end_time",
                        "calendar_interval": "quarter",
                        "format": "QQQQ"
                    }
                }
            }
        }
    }

    return aggs


def format_quarter_aggs(aggs):
    year_filter = aggs.pop("year_filter")
    for bucket in year_filter["by_current_year_quarter"]["buckets"]:
        bucket['key'] = bucket['key_as_string']
    aggs["by_current_year_quarter"] = year_filter["by_current_year_quarter"]


async def curd_alumni_agg_by_activity(person_id, year):
    query = {
        "size": 0,
        "query": {
            "has_child": {
                "type": "member",
                "query": {
                    "terms": {
                        "person_id": [
                            person_id
                        ]
                    }
                }
            }
        }, 'aggs': get_quarter_aggs(year)}

    res = await es_client.search(index=Index_KJJ_ACTIVITY_REGISTER, body=query)

    aggs = res["aggregations"]
    format_quarter_aggs(aggs)
    by_current_year_quarter = aggs['by_current_year_quarter']['buckets']
    if not by_current_year_quarter:
        # preset value
        aggs['by_current_year_quarter']['buckets'] = [{'doc_count': 0,
                                                       'key': 'Q1',
                                                       'key_as_string': 'Q1'},
                                                      {'doc_count': 0,
                                                       'key': 'Q2',
                                                       'key_as_string': 'Q2'},
                                                      {'doc_count': 0,
                                                       'key': 'Q3',
                                                       'key_as_string': 'Q3'},
                                                      {'doc_count': 0,
                                                       'key': 'Q4',
                                                       'key_as_string': 'Q4'}]

    else:
        has_quarter_set = {q.get("key") for q in by_current_year_quarter}
        quarter_set = {"Q1", "Q2", "Q3", 'Q4'}

        not_in_quarter = quarter_set - has_quarter_set

        for q in not_in_quarter:
            loc_str = q[1:2]
            loc = int(loc_str) - 1
            aggs['by_current_year_quarter']['buckets'].insert(loc, {'doc_count': 0,
                                                                    'key': q,
                                                                    'key_as_string2': q})

    return {"total": 0, "items": [], "aggregation": aggs}


async def curd_get_register_records_by_activity(params):
    """
     # 校友参加的活动列表 包括聚类
    """
    page = params.offset
    size = params.size
    person_id = params.filter.pop("person_id")
    query = {
        "from": (page - 1) * size,
        "size": size,
        "query": {
            "has_child": {
                "type": "member",
                "query": {
                    "terms": {
                        "person_id": [
                            person_id
                        ]
                    }
                }
            }
        },
    }

    agg_stage = {
        "by_activity_year": {
            "terms": {
                "field": "range_year"
            }
        },
        "by_activity_type": {
            "terms": {
                "field": "activity_type.keyword"
            }
        },
        "by_host_and_coop": {
            "terms": {
                "field": "host_label.institution_name.keyword"
            },
            "aggs": {
                "ids": {
                    "terms":
                        {
                            "field": "host_label.id",
                            "size": 1
                        }
                }
            }
        }

    }
    # agg_stage.update(get_quarter_aggs())  # 人才详情参页与活动直方图
    query['aggs'] = agg_stage

    res = await es_client.search(index=Index_KJJ_ACTIVITY_REGISTER, body=query)

    items = res['hits']['hits']
    total = res["hits"]["total"]["value"]
    aggs = res["aggregations"]

    for host in aggs["by_host_and_coop"]["buckets"]:
        ids_buckets = host.get("ids").get("buckets")
        if ids_buckets:
            host["id"] = ids_buckets[0].get("key")
        else:
            host["id"] = 0

        del host["ids"]

    data = []
    for item in items:
        data.append(item['_source'])

    return {"total": total, "items": data, "aggregation": aggs}


async def curd_get_register_records_by_person(params):
    """ 活动参与人列表
        根据活动id 获得人列表
       """

    activity_id = params.filter.pop("activity_id")
    register_query = {
        "_source": "person_id",
        "query": {
            "has_parent": {
                "parent_type": "activity",
                "query": {
                    "ids": {"values": [activity_id]}
                }
            }
        }
    }
    _key = f"act::persons::{activity_id}"
    cache_person_ids = aredis.get(_key)
    if cache_person_ids:
        person_ids = orjson.loads(cache_person_ids)

    else:

        resp = async_scan(es_client, index=Index_KJJ_ACTIVITY_REGISTER, body=register_query, scroll="6s",
                          size=5000)
        person_ids = []
        async for doc in resp:
            person_ids.append(doc["_source"].get("person_id"))

        aredis.set(_key, orjson.dumps(person_ids), ex=60)

    offset = int(params.offset)
    size = int(params.size)

    person_query = {
        "from": (offset - 1) * size,
        "size": size,
        "query": {
            "bool": {
                "must": [
                    {
                        "ids": {
                            "values": person_ids
                        }
                    }
                ]
            }
        }
    }
    res = await es_client.search(index=Index_KJJ_ALUMNI, body=person_query)
    items = res['hits']['hits']
    total = res["hits"]["total"]["value"]

    data = []
    for item in items:
        data.append(item['_source'])

    return {"total": total, "items": data, "aggregation": []}


async def crud_alumni_by_id(alumni_id):
    # todo 根据
    query = {
        "from": 0,
        "size": 1,
        "query": {
            "bool": {
                "must": [
                    {
                        "ids": {
                            "values": [
                                alumni_id
                            ]
                        }
                    }
                ],
                "should": [],
                "filter": [
                    {
                        "range": {
                            "number_of_applicants": {
                                "gt": 0
                            }
                        }
                    }
                ]
            }
        }
    }
    res = await es_client.search(index=Index_KJJ_ALUMNI, body=query)
    total = res["hits"]["total"]["value"]
    items = res['hits']['hits']
    data = []
    for item in items:
        item['_source']['activation_detail'] = []
        item['_source']['top_ranking'] = item['_source'].get("rank_alumni_score", 0)
        data.append(item['_source'])

    return {"total": total, "items": data, "aggregation": None}


async def crud_person_activation_list(alumni_id, page=1, size=10):
    # 获得活跃度的数据列表
    person_query = {
        "_source": ["id", "name", "score_importance_of_activities", "score_importance_of_role"],
        "from": (page - 1) * size,
        "size": size,
        "query": {
            "has_child": {
                "type": "member",
                "query": {
                    "term": {
                        "person_id": {
                            "value": alumni_id
                        }
                    }
                }
            }
        },
        "aggs": {
            "members": {
                "children": {
                    "type": "member"
                },
                "aggs": {
                    "alumni_score": {
                        "filter": {
                            "term": {
                                "person_id": alumni_id
                            }
                        },
                        "aggs": {
                            "activity_filter": {
                                "terms": {
                                    "field": "activity_id",
                                    "size": 10000,
                                },
                                "aggs": {
                                    "score_score": {
                                        "sum": {
                                            "field": "score_importance_of_role"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    res_person = await es_client.search(index=Index_KJJ_ACTIVITY_REGISTER, body=person_query)
    items_act_person = res_person['hits']['hits']
    total = res_person["hits"]["total"]["value"]
    items_act_scores = res_person['aggregations']['members']['alumni_score']['activity_filter']['buckets']
    act_agg_list = []  # 活动活跃度得分列表
    act_agg_score = []  # 活动得分

    for act in items_act_person:
        # 一个活动联系人的得分。
        act_score = [b.get("score_score").get("value", 1) for b in items_act_scores if
                     b.get("key") == act.get("_id")]
        if not act_score:
            print(act, items_act_scores)

        act["_source"]['score_importance_of_role'] = int(act_score[0]) if act_score else 1
        # 计算总分
        act_agg_score.append(
            int(act["_source"]['score_importance_of_role']) * act["_source"]['score_importance_of_activities'])
        act_agg_list.append(act["_source"])

    return {"total": total, "items": act_agg_list, "aggregation": None}


async def crud_institution_info(institution_id, year=None):
    """获得机构的统计数值"""
    year = year or datetime.utcnow().year
    query = {
        "_source": ["m_activity_overview", "m_contact_overview", "oindex", "m_activity_span"],
        "query": {"bool": {"must": [{
            "term": {
                "_id": institution_id
            }
        }]}}
    }
    res = await es_client.search(index=Index_KJJ_DEPARTMENT, body=query)
    items = res['hits']['hits']
    data = []
    for item in items:
        # 雷达图
        db_oindex = item['_source']['oindex']
        oindex_one = [value for value in db_oindex if value.get("year", year) == year]
        item['_source']['oindex'] = oindex_one
        # 组织活动
        db_m_activity_overview = item['_source']['m_activity_overview']
        m_activity_overview = [value for value in db_m_activity_overview if value.get("year", year) == year]
        item['_source']['m_activity_overview'] = m_activity_overview
        # 联系人才
        db_m_contact_overview = item['_source']['m_contact_overview']
        m_contact_overview = [value for value in db_m_contact_overview if value.get("year", year) == year]
        item['_source']['m_contact_overview'] = m_contact_overview

        # 年份持续分布
        db_m_activity_span = item['_source'].get("m_activity_span", [])
        m_activity_span = [value for value in db_m_activity_span if value.get("year", year) == year]
        item['_source']['m_activity_span'] = m_activity_span

        item['_source']['oindex'] = oindex_one
        data.append(item['_source'])

    return data


async def crud_register_agg_by_act_type(institution_id=None, year=None):
    "活动类型的统计"
    year = year or datetime.utcnow().year
    query = {
        "query": {
            "bool": {
                "must": [
                    {"has_parent": {
                        "parent_type": "activity",
                        "query": {
                            "bool": {
                                "must": [
                                    bool_institution_query(institution_id)
                                ],
                                "filter": {"term": {
                                    "range_year": {
                                        "value": year

                                    }
                                }}
                            }
                        }
                    }}
                ]
            }
        },
        "aggs": {
            "by_register_act_type": {
                "terms": {
                    "field": "act_type.keyword"
                }
            }
        }
    }
    res = await es_client.search(index=Index_KJJ_ACTIVITY_REGISTER, body=query)

    aggs = res["aggregations"]

    return {"total": 0, "items": None, "aggregation": aggs}


def format_group_applicants_by_month_aggs(aggs):
    for bucket in aggs['group_applicants_by_month']['buckets']:
        bucket['doc_count'] = bucket['child_count']['doc_count']


async def cur_activity_by_institution(institution_id, year=None):
    year = year or datetime.utcnow().year
    query = {
        "size": 0,
        "query": {
            "bool": {
                "must": [
                    {"term": {"range_year": year}},
                    {
                        "term": {
                            "activity_member": {
                                "value": "activity"
                            }
                        }
                    },
                    bool_institution_query(institution_id)
                ]
            }
        },

    }

    aggs = {
        "by_importance_of_activities": {
            "terms": {
                "field": "importance_of_activities.keyword"
            }
        },
        "by_activities_type": {
            "terms": {
                "field": "activity_type.keyword"
            }
        },
        "by_month": {
            "date_histogram": {
                "field": "end_time",
                "calendar_interval": "month",
                "format": "yyyy-MM",
                "extended_bounds": {
                    "min": f"{year}-01",
                    "max": f"{year}-12"
                }
            }
        },
        "by_quarter": {
            "date_histogram": {
                "field": "end_time",
                "calendar_interval": "quarter",
                "format": "Q"
            }
        },
        "group_applicants_by_month": {
            "date_histogram": {
                "field": "end_time",
                "calendar_interval": "month",
                "format": "yyyy-MM",
                "extended_bounds": {
                    "min": f"{year}-01",
                    "max": f"{year}-12"
                }
            },
            "aggs": {
                "child_count": {
                    "children": {
                        "type": "member"
                    }
                }
            }
        },
        "group_applicants_by_quarter": {
            "date_histogram": {
                "field": "end_time",
                "calendar_interval": "quarter",
                "format": "Q"
            },
            "aggs": {
                "group_by_applicants": {
                    "sum": {
                        "field": "number_of_applicants"
                    }
                }
            }
        },
        "by_region": {
            "terms": {
                "field": "region.keyword"
            }
        },
        "by_province": {
            "terms": {
                "field": "province.keyword",
                "size": 100
            }
        }
    }
    query['aggs'] = aggs

    res = await es_client.search(index=Index_KJJ_ACTIVITY_REGISTER, body=query)

    aggs = res["aggregations"]
    format_group_applicants_by_month_aggs(aggs)

    return {"total": 0, "items": None, "aggregation": aggs}


async def cur_activity_by_alumni(institution_id, year=None):
    year = year or datetime.utcnow().year

    register_query = {
        "_source": "person_id",
        "query": {
            "has_parent": {
                "parent_type": "activity",
                "query": {"bool": {
                    "filter": {"term": {"range_year": year}},
                    "must": [bool_institution_query(institution_id)]
                }}
            }
        }
    }

    res = await es_client.search(index=Index_KJJ_ACTIVITY_REGISTER, body=register_query, size=10000)

    items = res['hits']['hits']

    person_ids = list({item["_source"]['person_id'] for item in items})
    person_query = {
        "size": 0,
        "query": {
            "bool": {
                "must": [
                    {
                        "ids": {
                            "values": person_ids
                        }
                    }
                ],
                "filter": [
                    {
                        "range": {
                            "number_of_applicants": {
                                "gt": 0
                            }
                        }
                    }
                ]
            }
        }
    }
    aggs = {
        "by_regions": {
            "terms": {
                "field": "region.keyword",
                "size": 20
            }
        },
        "by_province": {
            "terms": {
                "field": "job_province.keyword",
                "size": 50
            }
        },
        "by_subject": {
            "terms": {
                "field": "subject",
                "size": 15
            }
        }
    }
    person_query['aggs'] = aggs
    res = await es_client.search(index=Index_KJJ_ALUMNI, body=person_query)
    aggs = res["aggregations"]

    return {"total": 0, "items": None, "aggregation": aggs}


async def crud_get_alunmi_by_institution_id(institution_id, page=1, size=10):
    # deprecated year filter
    offset = (page - 1) * size
    if size == 0:
        size = 5000
    person_query = {
        "size": size,
        "from": offset,
        "query": {
            "bool": {
                "must": [
                    {"terms": {
                        "belongs_inst": [
                            institution_id
                        ]
                    }},
                    {
                        "range": {
                            "number_of_applicants": {
                                "gt": 0
                            }
                        }
                    }
                ]
            }
        }
    }
    res = await es_client.search(index=Index_KJJ_ALUMNI, body=person_query, size=size)
    items = res['hits']['hits']
    total = res["hits"]["total"]["value"]
    data = []
    for item in items:
        item['_source']["id"] = item['_source']["person_id"] = item['_id']
        data.append(item['_source'])

    return {"total": total, "items": data, "aggregation": []}


async def get_activity_data(query, from_, size):
    query["aggs"] = {
        "members": {
            "children": {"type": "member"},
            "aggs": {
                "avaiable": {
                    "filter": {"term": {"is_attended": True}},
                    "aggs": {"count": {"terms": {"field": "activity_id", "size": 20000}}},
                }
            }
        }
    }
    res = await es_client.search(index=Index_KJJ_ACTIVITY_REGISTER, body=query, from_=from_, size=size)
    items = res['hits']['hits']
    members = res["aggregations"]["members"]["avaiable"]["count"]["buckets"]
    activity_id2people_num = {b['key']: b['doc_count'] for b in members}
    data = []
    for item in items:
        item["_source"]["numOfParticipants"] = activity_id2people_num.get(item['_id'], 0)
        data.append(item['_source'])
    return data


async def crud_get_act_by_institution_id(institution_id, page=1, size=10):
    from_ = (page - 1) * size
    if size == 0:
        size = 5000
    query = {
        "from": from_,
        "size": size,
        "query": {
            "bool": {
                "filter": [
                    {
                        "bool": {
                            "minimum_should_match": 1,
                            "should": [
                                {"term": {"host_label.id": {"value": institution_id}}},
                                {
                                    "nested": {
                                        "path": "coop_labels",
                                        "query": {"term": {"coop_labels.id": institution_id}}
                                    }
                                },
                            ]}
                    }
                ]
            }
        }
    }
    res = await es_client.search(index=Index_KJJ_ACTIVITY_REGISTER, body=query)
    items = res['hits']['hits']
    total = res["hits"]["total"]["value"]
    data = []
    for item in items:
        item["_source"]["numOfParticipants"] = item["_source"]["number_of_applicants"]
        data.append(item['_source'])

    return {"total": total, "items": data, "aggregation": []}
